//-- Namespace --
if (typeof wildpack === 'undefined') { wildpack = {}; }

wildpack.SimpleDatexM = new Class({
    Implements: [Events, Options],

    //-- Constructor --
    initialize: function() {
        this._target = '';
        this._class = '';
        this._stateid = '';
        this.Data = [];
        this.Index = -1;
        this.Loaded = false;
    },
    
    //-- The callback for all request (synchro of data) --
    _baseCb: function(d, t) {
    	this.Data = d.data;
        this.Loaded = d.loaded;
        this._isNew = d._isNew;
        this._stateid = d.stateid;
        
        if (d.error !== '') {
        	this.fireEvent('error', d.error);
        	return false;
        }
        
        return true;
    },
    
  //-- Performs the request --
    _doReq: function(method, param, cb)
    {
    	var jr = new Request.JSON({
            url: this._target,
            onSuccess: function(d, t) {
  	        	var chk = this._baseCb(d, t);
	            if(typeof cb === 'function') {
	                cb.run([this, d.returnvalue, chk]);
	            }
            }.bind(this)
        });
        jr.get({
            cls: this._class,
            method: method,
            param: param,
            index: this.Index,
            stateid: this._stateid
        });
    },

    /**
     * Add a dataset to the object
     * @param {Object} data The fieldnames and values of the dataset to add
     * @param {Function} cb The callback function
     */
    add: function(data, cb) {
        var p = JSON.encode([data]);
        this._doReq('add', p, cb);
    },
    
    /**
     * Counts data in the database
     * @param {Object} condition The fieldnames and values used for count condition
     * @param {Function} cb The callback function
     */
    count: function(condition, cb) {
        var p = JSON.encode([condition]);
        this._doReq('count', p, cb);
    },
    
    /**
     * Moves the internal index to next dataset specified by fieldname and expected value. Omitting 
     * attribtues will indexing the next dataset. If the index was moved to an invalid entry, the function 
     * will return false, otherwise true. It is possible to loop like this: while(findNext(...)) 
     * @param {String} fieldname The name of the field used for lookup
     * @param {Object} value The value to use for lookup
     * @param {String} method The comparison method. Either "equal" or "not equal"
     */
    findNext: function(fieldname, value, method)
    {
    	fieldname = !fieldname ? '' : fieldname;
    	value = !value ? '' : value;
    	method = !method ? 'equal' : method;
    	
    	this.Index++;

		if (this.Index > this.Data.length-1) {
			this.Index = -1;
			return false;
		}
		
		for (this.Index; this.Index<this.Data.length; this.Index++)
		{
			if (fieldname === '') {
				return true;
			} else {
				switch (method) {
					case 'equal' : 
						if (this.Data[this.Index][fieldname] === value) {
							return true;
						} break;
					case 'not equal' :
						if (this.Data[this.Index][fieldname] !== value) {
							return true;
						} break;
				}
			}
		}
		
		this.Index = -1;
		return false;
    },
    
    /**
     * Retrieves the value of the field specified by name for the currently indexed dataset
     */
    get: function(fieldname)
    {
    	if (this.Index > -1 && this.Index < this.Data.length) {
			if (this.Data[this.Index][fieldname]) {
				return this.Data[this.Index][fieldname];
			}
		}
		return null;
    },
    
    /**
     * Retrieves the number of loaded datasets
     */
    length: function()
    {
    	return this.Data.length;
    },
    
    /**
     * Loads data to the object
     * @param {Object} condition Fieldnames and value used to select the data to load
     * @param {String} sort The fields (separated by colon) to order by
     * @param {String} dir The sort direction (either ASC or DESC)
     * @param {Number} limit The max. number of datasets to return
     * @param {Number} start The starting dataset when using limit
     * @param {Function} cb The callback function
     */
    load: function(condition, sort, dir, limit, start, cb)
    {
    	var p = JSON.encode([condition, sort, dir, limit, start]);
    	this._doReq('load', p, cb);
    },
    
    /**
     * Permanently deletes all loaded datasets
     * @param {Function} cb The callback function
     */
    remove: function(cb)
    {
        this._doReq('remove', '', cb);
    },
    
    /**
     * Resets the object
     */
    reset: function()
    {
    	
    },
    
    /**
     * Rewinds the internal index. It will be set to the position before the first dataset
     */
    rewind: function()
    {
    	this.Index = -1;
    },
    
    /**
     * Save all loaded datasets
     * @param {Function} cb The callback function
     */
    save: function(cb)
    {
    	this._doReq('save', '', cb);
    },
    
    /**
     * Set a field value for either one or all loaded datasets
     * @param {String} fieldname The name of the field to set
     * @param {Object} value The value to set the field to
     * @param {Boolean] all True to change all loaded datasets, false to only change the currently
     * indexed dataset
     * @param {Function} cb The callback function
     */
    set: function(fieldname, value, all, cb)
    {
    	var p = JSON.encode([fieldname, value, all]);
    	this._doReq('set', p, cb);
    },
    
    /**
     * Get the data of this object either as SimpleDatexS or as object/array
     * @param {Object} target The object (SimpleDatexS) to fill with the data of the current index
     * @param {Boolean} all True to export all datasets (as array of objects) false to export only the currently 
     * indexed dataset
     * @return Either the filled target object, a standard object or an array of objects
     */
    to: function(target, all)
    {
    	var f = this.getFields();
    	var o, i;
    	
    	if (all === false) {
    		o = {};
    		for (i=0; i<f.length; i++) {
    			o[f[i]] = this.get(f[i]);
    		}
    		
    		if (!target) {
    			return o;
    		}
    		target._isNew = this.Data[this.Index]._new === true ;
    		target.Data = o;
    		return target;
    	}
    	
    	var ret = [];
    	var bupIndex = this.Index;
    	this.rewind();
    	while(this.findNext()) {
    		o = {};
    		for (i=0; i<f.length; i++) {
    			o[f[i]] = this.get(f[i]);
    		}
    		ret.push(o);
    	}
    	
    	return ret;
    }
});
